/******************************************************************************\
    ContestContestantProblemDataBase.h discribes a database of submits.
    It's used with acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once

#include ".\BaseDataBase.hpp"
#include <Common\Plugin.h>

namespace nsContestContestantProblemDataBase
{
	//const char CODE_FILE_NAME[] = "contest_contestant_problem_code.fsb";

	const unsigned long FLAG_NO_REJUDGE = 0x00000001ul;

	struct sContestContestantProblemData0
	{
		unsigned long Key;
		unsigned long ContestContestantId;
		unsigned long ContestProblemId;
		unsigned long LanguageId;
		unsigned long Time;
		long Result;
		unsigned short TestNumber;
		unsigned long RunTime;
		unsigned long Memory;
		unsigned long Code;
		unsigned long CodeSize;
		unsigned long CompilationError;
		unsigned long CompilationErrorSize;
	};

	struct sContestContestantProblemData1
	{
		unsigned long Key;
		unsigned long ContestContestantId;
		unsigned long ContestProblemId;
		unsigned long LanguageId;
		unsigned long RelativeTime;
		long Result;
		unsigned short TestNumber;
		unsigned long RunTime;
		unsigned long Memory;
		unsigned long Code;
		unsigned long CodeSize;
		unsigned long CompilationError;
		unsigned long CompilationErrorSize;
		unsigned long Ip;
		unsigned long long RealTime;
		unsigned long Flags;
	};

	typedef sContestContestantProblemData1 sContestContestantProblemData;

	void ConversionFunction0( void *new_data, const void *prev_data );

	const sConversionTable ConversionTable[] =
	{
		{ sizeof( sContestContestantProblemData0 ), sizeof( sContestContestantProblemData1 ), &ConversionFunction0 }
	};

	struct ContestContestantIdCompare : public std::binary_function< cDataPointer< sContestContestantProblemData >, cDataPointer< sContestContestantProblemData >, bool >
	{
		bool operator()( const cDataPointer< sContestContestantProblemData > &left, const cDataPointer< sContestContestantProblemData > &right ) const
		{
			return left->ContestContestantId < right->ContestContestantId ||
				left->ContestContestantId == right->ContestContestantId && 
				( left->RelativeTime < right->RelativeTime ||
				  left->RelativeTime == right->RelativeTime && left->Key < right->Key );
		}
	};

	struct ContestContestantProblemCompare : public std::binary_function< cDataPointer< sContestContestantProblemData >, cDataPointer< sContestContestantProblemData >, bool >
	{
		bool operator()( const cDataPointer< sContestContestantProblemData > &left, const cDataPointer< sContestContestantProblemData > &right ) const
		{
			return left->ContestContestantId < right->ContestContestantId ||
				left->ContestContestantId == right->ContestContestantId && 
				( left->ContestProblemId < right->ContestProblemId ||
				  left->ContestProblemId == right->ContestProblemId && 
				  ( left->RelativeTime < right->RelativeTime ||
				    left->RelativeTime == right->RelativeTime && left->Key < right->Key ) );
		}
	};

	struct ContestProblemIdCompare : public std::binary_function< cDataPointer< sContestContestantProblemData >, cDataPointer< sContestContestantProblemData >, bool >
	{
		bool operator()( const cDataPointer< sContestContestantProblemData > &left, const cDataPointer< sContestContestantProblemData > &right ) const
		{
			return left->ContestProblemId < right->ContestProblemId ||
				left->ContestProblemId == right->ContestProblemId && 
				( left->RelativeTime < right->RelativeTime ||
				  left->RelativeTime == right->RelativeTime && left->Key < right->Key );
		}
	};

	struct LanguageIdCompare : public std::binary_function< cDataPointer< sContestContestantProblemData >, cDataPointer< sContestContestantProblemData >, bool >
	{
		bool operator()( const cDataPointer< sContestContestantProblemData > &left, const cDataPointer< sContestContestantProblemData > &right ) const
		{
			return left->LanguageId < right->LanguageId ||
				    left->LanguageId == right->LanguageId && left->Key < right->Key;
		}
	};

	typedef cBaseDataBase< sContestContestantProblemData >::KeyIterator KeyIterator;
	typedef cBaseDataBase< sContestContestantProblemData >::KeyReverseIterator KeyReverseIterator;
	typedef cPublicIterator< sContestContestantProblemData, ContestContestantIdCompare > ContestContestantIdIterator;
	typedef cPublicIterator< sContestContestantProblemData, ContestContestantIdCompare, typename std::set< cDataPointer< sContestContestantProblemData >, ContestContestantIdCompare >::const_reverse_iterator > ContestContestantIdReverseIterator;
	typedef cPublicIterator< sContestContestantProblemData, ContestContestantProblemCompare > ContestContestantProblemIterator;
	typedef cPublicIterator< sContestContestantProblemData, ContestProblemIdCompare > ContestProblemIdIterator;
	typedef cPublicIterator< sContestContestantProblemData, ContestProblemIdCompare, typename std::set< cDataPointer< sContestContestantProblemData >, ContestProblemIdCompare >::const_reverse_iterator > ContestProblemIdReverseIterator;
	typedef cPublicIterator< sContestContestantProblemData, LanguageIdCompare > LanguageIdIterator;

	class cWardContestContestantProblemDataBase : public cBaseDataBase< sContestContestantProblemData >
	{
	private:
		std::set< cDataPointer< sContestContestantProblemData >, ContestContestantIdCompare > ContestContestantIdIndex;
		std::set< cDataPointer< sContestContestantProblemData >, ContestContestantProblemCompare > ContestContestantProblemIndex;
		std::set< cDataPointer< sContestContestantProblemData >, ContestProblemIdCompare > ContestProblemIdIndex;
		std::set< cDataPointer< sContestContestantProblemData >, LanguageIdCompare > LanguageIdIndex;
	protected:
		virtual bool Indexed( const cDataPointer< sContestContestantProblemData > &data_pointer )
		{
			//return ContestContestantIdIndex.find( data_pointer ) != ContestContestantIdIndex.end() ||
			//	ContestContestantProblemIndex.find( data_pointer ) != ContestContestantProblemIndex.end() ||
			//	ContestProblemIdIndex.find( data_pointer ) != ContestProblemIdIndex.end() ||
			//	LanguageIdIndex.find( data_pointer ) != LanguageIdIndex.end();
			return false;
		}
		virtual void InsertIndex( const cDataPointer< sContestContestantProblemData > &data_pointer )
		{
			ContestContestantIdIndex.insert( data_pointer );
			ContestContestantProblemIndex.insert( data_pointer );
			ContestProblemIdIndex.insert( data_pointer );
			LanguageIdIndex.insert( data_pointer );
		}
		virtual void UpdateIndex( const cDataPointer< sContestContestantProblemData > &data_pointer, unsigned long index )
		{
			ContestContestantIdIndex.find( data_pointer )->Index = index;
			ContestContestantProblemIndex.find( data_pointer )->Index = index;
			ContestProblemIdIndex.find( data_pointer )->Index = index;
			LanguageIdIndex.find( data_pointer )->Index = index;
		}
		virtual void DeleteIndex( const cDataPointer< sContestContestantProblemData > &data_pointer )
		{
			ContestContestantIdIndex.erase( data_pointer );
			ContestContestantProblemIndex.erase( data_pointer );
			ContestProblemIdIndex.erase( data_pointer );
			LanguageIdIndex.erase( data_pointer );
		}
		virtual void ClearIndex()
		{
			ContestContestantIdIndex.clear();
			ContestContestantProblemIndex.clear();
			ContestProblemIdIndex.clear();
			LanguageIdIndex.clear();
		}
	public:
		cWardContestContestantProblemDataBase( /*bool auto_update*/ )
			: cBaseDataBase( /*auto_update*/ )
		{
		}
		ContestContestantIdIterator BeginByContestContestantId() const
		{
			return ContestContestantIdIterator( ContestContestantIdIndex.begin() );
		}
		ContestContestantIdIterator LowerBoundByContestContestantId( unsigned long contest_contestant_id ) const 
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.ContestContestantId = contest_contestant_id;
			contest_contestant_problem_data.RelativeTime = 0;
			contest_contestant_problem_data.Key = 0;
			return ContestContestantIdIterator( ContestContestantIdIndex.lower_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		ContestContestantIdIterator UpperBoundByContestContestantId( unsigned long contest_contestant_id ) const
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.ContestContestantId = contest_contestant_id;
			contest_contestant_problem_data.RelativeTime = 0xfffffffful;
			contest_contestant_problem_data.Key = 0xfffffffful;
			return ContestContestantIdIterator( ContestContestantIdIndex.upper_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		ContestContestantIdIterator EndByContestContestantId() const
		{
			return ContestContestantIdIterator( ContestContestantIdIndex.end() );
		}
		ContestContestantIdReverseIterator ReverseBeginByContestContestantId() const
		{
			return ContestContestantIdReverseIterator( EndByContestContestantId() );
		}
		ContestContestantIdReverseIterator ReverseLowerBoundByContestContestantId( unsigned long contest_contestant_id ) const 
		{
			return ContestContestantIdReverseIterator( UpperBoundByContestContestantId( contest_contestant_id ) );
		}
		ContestContestantIdReverseIterator ReverseUpperBoundByContestContestantId( unsigned long contest_contestant_id ) const
		{
			return ContestContestantIdReverseIterator( LowerBoundByContestContestantId( contest_contestant_id ) );
		}
		ContestContestantIdReverseIterator ReverseEndByContestContestantId() const
		{
			return ContestContestantIdReverseIterator( BeginByContestContestantId() );
		}
		ContestContestantProblemIterator BeginByContestContestantProblem() const
		{
			return ContestContestantProblemIterator( ContestContestantProblemIndex.begin() );
		}
		ContestContestantProblemIterator LowerBoundByContestContestantProblem( unsigned long contest_contestant_id, unsigned long contest_problem_id ) const
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.ContestContestantId = contest_contestant_id;
			contest_contestant_problem_data.ContestProblemId = contest_problem_id;
			contest_contestant_problem_data.RelativeTime = 0;
			contest_contestant_problem_data.Key = 0;
			return ContestContestantProblemIterator( ContestContestantProblemIndex.lower_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		ContestContestantProblemIterator UpperBoundByContestContestantProblem( unsigned long contest_contestant_id, unsigned long contest_problem_id ) const
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.ContestContestantId = contest_contestant_id;
			contest_contestant_problem_data.ContestProblemId = contest_problem_id;
			contest_contestant_problem_data.RelativeTime = 0xfffffffful;
			contest_contestant_problem_data.Key = 0xfffffffful;
			return ContestContestantProblemIterator( ContestContestantProblemIndex.upper_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		ContestContestantProblemIterator EndByContestContestantProblem() const
		{
			return ContestContestantProblemIterator( ContestContestantProblemIndex.end() );
		}
		ContestProblemIdIterator BeginByContestProblemId() const
		{
			return ContestProblemIdIterator( ContestProblemIdIndex.begin() );
		}
		ContestProblemIdIterator LowerBoundByContestProblemId( unsigned long contest_problem_id ) const
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.ContestProblemId = contest_problem_id;
			contest_contestant_problem_data.RelativeTime = 0;
			contest_contestant_problem_data.Key = 0;
			return ContestProblemIdIterator( ContestProblemIdIndex.lower_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		ContestProblemIdIterator UpperBoundByContestProblemId( unsigned long contest_problem_id ) const
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.ContestProblemId = contest_problem_id;
			contest_contestant_problem_data.RelativeTime = 0xfffffffful;
			contest_contestant_problem_data.Key = 0xfffffffful;
			return ContestProblemIdIterator( ContestProblemIdIndex.upper_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		ContestProblemIdIterator EndByContestProblemId() const
		{
			return ContestProblemIdIterator( ContestProblemIdIndex.end() );
		}
		ContestProblemIdReverseIterator ReverseBeginByContestProblemId() const
		{
			return ContestProblemIdReverseIterator( EndByContestProblemId() );
		}
		ContestProblemIdReverseIterator ReverseLowerBoundByContestProblemId( unsigned long contest_problem_id ) const
		{
			return ContestProblemIdReverseIterator( UpperBoundByContestProblemId( contest_problem_id ) );
		}
		ContestProblemIdReverseIterator ReverseUpperBoundByContestProblemId( unsigned long contest_problem_id ) const
		{
			return ContestProblemIdReverseIterator( LowerBoundByContestProblemId( contest_problem_id ) );
		}
		ContestProblemIdReverseIterator ReverseEndByContestProblemId() const
		{
			return ContestProblemIdReverseIterator( BeginByContestProblemId() );
		}
		LanguageIdIterator BeginByLanguage() const
		{
			return LanguageIdIterator( LanguageIdIndex.begin() );
		}
		LanguageIdIterator LowerBoundByLanguageId( unsigned long language_id ) const
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.LanguageId = language_id;
			contest_contestant_problem_data.Key = 0ul;
			return LanguageIdIterator( LanguageIdIndex.lower_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		LanguageIdIterator UpperBoundByLanguageId( unsigned long language_id ) const
		{
			sContestContestantProblemData contest_contestant_problem_data;
			contest_contestant_problem_data.LanguageId = language_id;
			contest_contestant_problem_data.Key = 0xfffffffful;
			return LanguageIdIterator( LanguageIdIndex.upper_bound( cDataPointer< sContestContestantProblemData >( &contest_contestant_problem_data ) ) );
		}
		LanguageIdIterator EndByLanguageId() const
		{
			return LanguageIdIterator( LanguageIdIndex.end() );
		}
	};

	class cContestContestantProblemDataBase : public cPointerObject< cWardContestContestantProblemDataBase >
	{
	public:
		bool Create( /*bool auto_update = false*/ )
		{
			cWardContestContestantProblemDataBase *ward_contest_contestant_problem_data_base;
			try
			{
				ward_contest_contestant_problem_data_base = new cWardContestContestantProblemDataBase( /*auto_update*/ );
			}
			catch( ... )
			{
				return false;
			}
			if( !SwitchToWardObject( ward_contest_contestant_problem_data_base ) )
			{
				delete ward_contest_contestant_problem_data_base;
				return false;
			}
			return true;
		}
		void Destroy()
		{
			SwitchToSubObject( NULL );
		}
	};
}
